use serde::{Deserialize, Serialize};

#[derive(Serialize)]
pub struct Login<T> {
    pub op: Option<i32>,
    pub d: Option<T>
}

#[derive(Serialize)]
pub struct Auth {
    pub token: Option<String>,
    pub intents: i32,
    pub shard: Vec<i32>,
    pub properties: Option<i32>
}

#[derive(Serialize)]
pub struct Reconnect {
    pub token: Option<String>,
    pub session_id: Option<String>,
    pub seq: Option<i32>
}

#[derive(Serialize)]
pub struct HeartBeat {
    pub op: Option<i32>,
    pub d: Option<i32>
}

#[derive(Serialize, Deserialize, Debug)]
pub struct GroupMessage {
    pub op: Option<i32>,
    pub s: Option<i32>,
    pub t: Option<String>,
    pub id: Option<String>,
    pub d: Option<Info>
}

#[derive(Serialize, Deserialize, Debug)]
pub struct Info {
    pub author: Author,
    pub content: String,
    pub group_id: String,
    pub group_openid: String,
    pub id: String,
    pub timestamp: String
}

#[derive(Serialize, Deserialize, Debug)]
pub struct Author {
    pub id: String,
    pub member_openid: String,
}

impl HeartBeat {
    pub fn new() -> HeartBeat {
        HeartBeat {
            op: Some(1),
            d: None,
        }
    }
}

impl Login<Auth> {
    pub fn new(token: Option<String>) -> Login<Auth> {
        Login {
            op: Some(2),
            d: Option::from(Auth {
                token,
                intents: 0 | 1 << 25 | 1 << 30,
                shard: vec![0, 1],
                properties: None,
            }),
        }
    }
}

impl Login<Reconnect> {
    pub fn new(token: Option<String>, session_id: Option<String>, seq: Option<i32>) -> Login<Reconnect> {
        Login {
            op: Some(6),
            d: Some(Reconnect {
                token,
                session_id,
                seq
            }),
        }
    }
}
